﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Diagnostics;
using System.Management;
using System.Runtime.InteropServices;
using Microsoft.Win32;
using System.Xml;

namespace CitrixSystemVerifier
{
    public partial class MainForm : Form
    {
        bool m_fIs64bitOS = false;
        List<Issue> IssuesList = new List<Issue> ();
        int CurrentIssue = 0;
        int LastIssue = 0;
        CommandLine m_CommandLine;

        Dictionary<string, Variable> Variables = new Dictionary<string, Variable>();

        List<RequiredInstalledComponent> RequiredInstalledComponents = new List<RequiredInstalledComponent> ();
        Dictionary<string, RequiredInstalledComponent> RequiredInstalledComponentsDictionary = new Dictionary<string, RequiredInstalledComponent>();

        List<RequiredFile> RequiredFiles = new List<RequiredFile> ();
        Dictionary<string, RequiredFile> RequiredFilesDictionary = new Dictionary<string, RequiredFile> ();

        List<RequiredProcess> RequiredProcesses = new List<RequiredProcess> ();

        List<RegistryValue> RequiredRegistryValues = new List<RegistryValue> ();
        Dictionary<string, RegistryValue> RequiredRegistryValuesDictionary = new Dictionary<string, RegistryValue>();

        Dictionary<string, Message> Messages = new Dictionary<string, Message> ();

#region Variables

        string GetVariable(string VariableName)
        {
            List<string> Variables = GetVariable(VariableName, null);
            if ((Variables == null) || (Variables.Count == 0))
                return null;
            return Variables[0];
        }

        List<string> GetVariable(string VariableName, string Context)
        {
            if (!Variables.ContainsKey(VariableName))
                return null;

            List<string> v = new List<string>();
            try
            {
                v = Variables[VariableName].GetContextValue(Context);
            }
            catch (Exception)
            {
                return null;
            }

            for (int i = 0; i < v.Count; i++ )
                v[i] = ResolveVariableString(v[i], Context);
            return v;
        }

        void SetVariable(string VariableName, string Value)
        {
            if (Variables.ContainsKey(VariableName))
                Variables[VariableName].Value = Value;
            else
                Variables.Add(VariableName, new Variable(Value));
        }

        void SetVariable(string VariableName, string Context, string Value)
        {
            if (Variables.ContainsKey(VariableName))
                Variables[VariableName].SetContextValue(Context, Value);
            else
                Variables.Add(VariableName, new Variable(Context, Value));
        }

        void AppendVariable(string VariableName, string Value)
        {
            string NewValue = GetVariable(VariableName);
            if (NewValue != null)
            {
                char[] delimiters = new char[] { ',' };
                string[] ParsedContext = NewValue.Split(delimiters);
                foreach (string s in ParsedContext)
                    if (s.Trim() == Value.Trim())
                        return;
                if (string.IsNullOrEmpty(NewValue))
                    NewValue = Value.Trim();
                else
                    NewValue += "," + Value.Trim();
                SetVariable(VariableName, NewValue);
            }
            else
                SetVariable(VariableName, Value);
        }

        string ResolveVariableString(string VariableString, string Context)
        {
            if (string.IsNullOrEmpty(VariableString))
                return null;

            string v = VariableString;

            if (v.Contains("$("))
            {
                int start = v.IndexOf("$(");
                int end = v.IndexOf(")", start);

                string VariableName2 = v.Substring(start, end - start + 1);
                List<string> v2 = GetVariable(VariableName2, Context);
                if (v2 != null)
                    v = v.Replace(VariableName2, v2[0]);
            }
            return v;
        }
#endregion
        public MainForm(ref CommandLine commandLine)
        {
            m_CommandLine = commandLine;

            InitializeComponent();
        }

        private void MainForm_Load(object sender, EventArgs e)
        {
            LoadProgressDialog dlg = new LoadProgressDialog(7);

            StatusTextBox.SelectionTabs = new int[] { 20, 40, 60, 80, 100, 120, 140, 160 };
            try
            {
                dlg.Show(this);

                StatusTextBox.AppendText(Application.ProductName + " " + Application.ProductVersion + "\n");
                StatusTextBox.AppendText(DateTime.Now.ToString() + "\n");

                string ConfigurationFile = "default.ctv";
                if (!string.IsNullOrEmpty(m_CommandLine.ConfigurationFile))
                    ConfigurationFile = m_CommandLine.ConfigurationFile;

                dlg.Update("Loading configuration");

                LoadConfiguration(ConfigurationFile);

                if (Variables.ContainsKey("$(Title)"))
                {
                    string Title = Variables["$(Title)"].Value;
                    if (!string.IsNullOrEmpty(Title))
                        Text = Title;
                }

                dlg.Update("Verifying System");
                VerifySystem();
                dlg.Update("Verifying Registry");
                VerifyRegistry();
                dlg.Update("Verifying Files");
                VerifyFiles();

                if (!m_CommandLine.CheckInstallOnly)
                {
                    dlg.Update("Verifying Current State");
                    CheckCurrentState();
                }
                dlg.Update("Analyzing");
                ShowAnalysis();
                dlg.Update("Updating");
                UpdateIssuesListView();
                dlg.Update("Done");
                IssuesListView.Items[CurrentIssue].Selected = true;
                if (!string.IsNullOrEmpty(m_CommandLine.File))
                {
                    try
                    {
                        SaveFile(m_CommandLine.File);
                    }
                    catch (System.IO.IOException ex)
                    {
                        MessageBox.Show(ex.Message, Application.ProductName, MessageBoxButtons.OK);
                    }
                }

                dlg.Update("Done");
                dlg.Close();

                if (m_CommandLine.AutoClose)
                {
                    Close();
                    return;
                }

                int NumberOfIssues = 0;
                Dictionary<string, int> IssueTable = new Dictionary<string, int>();

                foreach (Issue issue in IssuesList)
                    if (!string.IsNullOrEmpty(issue.Message))
                    {
                        if (Messages.ContainsKey(issue.Message))
                        {
                            string Type = Messages[issue.Message].Type;

                            if (IssueTable.ContainsKey(Type))
                                IssueTable[Type]++;
                            else
                                IssueTable[Type] = 1;
                            NumberOfIssues++;
                        }
                    }

                if (NumberOfIssues > 0)
                {
                    string Message = "";

                    string IssueTableString = "";
                    foreach (KeyValuePair<string, int> kv in IssueTable)
                    {
                        IssueTableString += "    " + kv.Key + " = " + kv.Value.ToString() + "\n";
                    }

                    Message = NumberOfIssues.ToString() + " total issue(s) were detected:\n" + IssueTableString + "\n";

                    string SupportEmail = "";
                    if (Variables.ContainsKey("$(SupportEmail)"))
                        SupportEmail = Variables["$(SupportEmail)"].Value;
                    if (!string.IsNullOrEmpty(SupportEmail))
                        Message += "Copy the report displayed after this message into an email\n" +
                                "and send to " +
                                SupportEmail + "\n";
                    MessageBox.Show(Message, Application.ProductName);
                }
                else
                {
                    string Message = "No issues were detected!\n";
                    string SupportEmail = Variables["$(SupportEmail)"].Value;
                    if (!string.IsNullOrEmpty(SupportEmail))
                        Message += "If you are still experiencing problems, copy the report displayed \n" +
                                "after this message into an email, add a brief description of the\n" +
                                "problem and send to " +
                                SupportEmail + "\n";
                    Message += "\nContinue to copy report?";
                    if (MessageBox.Show(Message,
                                Application.ProductName,
                                MessageBoxButtons.YesNo) == DialogResult.No)
                        Close();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, Application.ProductName, MessageBoxButtons.OK);
            }
        }

        #region StatusTextBox

        // Append text of the given color.
        void AppendText(RichTextBox box, Color color, string text)
        {
            int start = box.TextLength;
            box.AppendText(text);
            int end = box.TextLength;

            // Textbox may transform chars, so (end-start) != text.Length
            box.Select(start, end - start);
            {
                box.SelectionColor = color;
                // could set box.SelectionBackColor, box.SelectionFont too.
            }
            box.SelectionLength = 0; // clear
        }

        void AppendLineBreak(RichTextBox box)
        {
            box.AppendText("=========================================================================\n");
        }

        #endregion StatusTextBox

        bool CompareVersions(string v1, string v2)
        {
            if (string.IsNullOrEmpty(v1))
                return true;

            if (string.IsNullOrEmpty(v2))
                return true;

            char[] delimiters = new char[] {',', ' ', '.'};
            String[] v1Parts = v1.Split(delimiters);
            String[] v2Parts = v2.Split(delimiters);

            for (int i = 0; i < v1Parts.Length && i < v2Parts.Length; i++)
            {
                try
                {
                    int v1int = int.Parse(v1Parts[i].Trim());
                    int v2int = int.Parse(v2Parts[i].Trim());
                    if (v1int > v2int)
                        return false;
                    else if (v1int < v2int)
                        return true;
                }
                catch (FormatException)
                {
                    return false;
                }
            }
            return true;
        }

        public UInt64 GetRAMSize() 
        { 
            UInt64 total=0; 
            try 
            { 
                ManagementScope scope; 
                scope = new ManagementScope();
                ObjectQuery query = new ObjectQuery("SELECT * FROM Win32_ComputerSystem"); 
                ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query); 
                foreach (ManagementObject queryObj in searcher.Get())
                {
                    total = Convert.ToUInt64(queryObj["TotalPhysicalMemory"].ToString()); 
                }

                total = total / 1024; 
            }
            catch {} 
            {
                return total;
            }
        }

        private static ulong GetFreeDiskSpaceInKilobytes(string drive)
        {
            ManagementObject disk = new ManagementObject("win32_logicaldisk.deviceid=\"" + drive + ":\"");
            disk.Get();
            ulong FreeSpace = (ulong)disk["FreeSpace"] / 1024;
            return FreeSpace;
        }

        private void AppendInstalledComponents()
        {
            StatusTextBox.AppendText("\t" + "Installed Components" + "\n");
            string componentsKeyName = "SOFTWARE\\Microsoft\\Active Setup\\Installed Components",
               friendlyName,
               version;
            // Find out in the registry anything under:
            //    HKLM\SOFTWARE\Microsoft\Active Setup\Installed Components
            try
            {
                RegistryKey componentsKey = Registry.LocalMachine.OpenSubKey(componentsKeyName);
                string[] instComps = componentsKey.GetSubKeyNames();
                foreach (string instComp in instComps)
                {
                    RegistryKey key = componentsKey.OpenSubKey(instComp);
                    friendlyName = (string)key.GetValue(null); // Gets the (Default) value from this key
                    if (!string.IsNullOrEmpty(friendlyName))
                    {
                        // Let's try to get any version information that's available
                        version = (string)key.GetValue("Version");

                        // If you want only the framework info with its SP level and not the
                        // other hotfix and service pack detail, uncomment this if:
                        //    if(version!=null && version.Split(',').Length>=4)
                        StatusTextBox.AppendText("\t\t" + friendlyName + (version != null ? (" = " + version) : ""));

                        if (RequiredInstalledComponentsDictionary.ContainsKey(friendlyName))
                        {
                            if (!CompareVersions(RequiredInstalledComponentsDictionary[friendlyName].MinimumProductVersion, version))
                            {
                                IssuesList.Add(new Issue(StatusTextBox.SelectionStart));
                                AppendText(StatusTextBox, Color.Orange, " [BAD PRODUCT VERSION (Less than minimum)]");
                            }
                            else
                            {
                                string MaxVersion = RequiredInstalledComponentsDictionary[friendlyName].MaximumProductVersion;
                                if (MaxVersion != null && !CompareVersions(version, MaxVersion))
                                {
                                    IssuesList.Add(new Issue(StatusTextBox.SelectionStart));
                                    AppendText(StatusTextBox, Color.Orange, " [BAD PRODUCT VERSION (Greater than maximum)]");
                                }
                                else
                                {
                                    IssuesList.Add(new Issue(StatusTextBox.SelectionStart));
                                    AppendText(StatusTextBox, Color.Green, " [REQUIRED]");
                                    RequiredInstalledComponentsDictionary[friendlyName].Found = true;
                                    RequiredInstalledComponentsDictionary[friendlyName].FoundVersion = version;
                                    AppendText(StatusTextBox, Color.Green, " [GOOD PRODUCT VERSION]");
                                }
                            }

                        }

                        StatusTextBox.AppendText("\n");
                    }
                }
            }
            catch (Exception ex)
            {
                AppendText(StatusTextBox, Color.Orange, "[" + ex.Message + "]");
                StatusTextBox.AppendText("\n");
            }
        }

        private void VerifySystem()
        {
            AppendLineBreak(StatusTextBox);
            StatusTextBox.AppendText("System Verification\n");
            AppendLineBreak(StatusTextBox);
            StatusTextBox.AppendText("\t" + "OS = " + System.Environment.OSVersion.ToString());
            SetVariable("$(OSVersion)", System.Environment.OSVersion.ToString());
            AppendVariable("$(Context)", "OSVersion=" + System.Environment.OSVersion.Version.Major + "." +
                System.Environment.OSVersion.Version.Minor);

            string MinimumOSVersion = GetVariable("$(MinimumOSVersion)");
            if (MinimumOSVersion != null)
            {
                if (!CompareVersions(MinimumOSVersion, System.Environment.OSVersion.Version.ToString()))
                {
                    IssuesList.Add(new Issue(StatusTextBox.SelectionStart, "MessageBadOS"));
                    AppendText(StatusTextBox, Color.Red, "[BAD OS VERSION] " + GetMessageText("MessageBadOS"));
                }
                else
                {
                    IssuesList.Add(new Issue(StatusTextBox.SelectionStart));
                    AppendText(StatusTextBox, Color.Green, "[GOOD OS]");
                }
            }
            StatusTextBox.AppendText("\n");

            StatusTextBox.AppendText("\t" + "Version = " + System.Environment.Version.ToString() + "\n");
            m_fIs64bitOS = ((Marshal.SizeOf(typeof(IntPtr)) == 4) ? false : true);
            if (m_fIs64bitOS)
            {
                SetVariable("$(Wow6432NodeKey)", "\\Wow6432Node");
                AppendVariable("$(Context)", "64 Bit");
            }
            else
            {
                SetVariable("$(Wow6432NodeKey)", "");
                AppendVariable("$(Context)", "32 Bit");
            }

            string Context = Variables["$(Context)"].Value;

            try
            {
                StatusTextBox.AppendText("\t" + "Bits = " + (m_fIs64bitOS ? 64 : 32).ToString() + "\n");
                StatusTextBox.AppendText("\t" + "Processor Count = " + System.Environment.ProcessorCount.ToString() + "\n");
                StatusTextBox.AppendText("\t" + "Physical Memory = " + GetRAMSize().ToString() + "KB" + "\n");
                StatusTextBox.AppendText("\t" + "Free Disk Space = " + GetFreeDiskSpaceInKilobytes("C").ToString() + "KB" + "\n");
                StatusTextBox.AppendText("\t" + "Culture = " + System.Globalization.CultureInfo.CurrentCulture.ToString() + "\n");
            }
            catch (Exception ex)
            {
                AppendText(StatusTextBox, Color.Orange, "[" + ex.Message + "]");
                StatusTextBox.AppendText("\n");
            }

            for (int i = 0; i < RequiredInstalledComponents.Count; i++)
            {
                RequiredInstalledComponentsDictionary.Add(RequiredInstalledComponents[i].Name, RequiredInstalledComponents[i]);
            }

            AppendInstalledComponents();

            foreach (KeyValuePair<string, RequiredInstalledComponent> kv in RequiredInstalledComponentsDictionary)
            {
                if (!kv.Value.Found)
                {
                    if (kv.Value.Context == null || InContext(Context, kv.Value.Context))
                    {
                        IssuesList.Add(new Issue(StatusTextBox.SelectionStart, kv.Value.Message));
                        AppendText(StatusTextBox, Color.Red, "\t" + kv.Key + " [NOT FOUND] " + GetMessageText(kv.Value.Message) + "\n");
                    }
                }
            }

        }

        private string GetFileProductVersion (string Filename)
        {
            FileVersionInfo fVersionInfo = FileVersionInfo.GetVersionInfo(Filename);
            return fVersionInfo.ProductVersion;
        }

        private void AppendFile(RichTextBox box, string Filename)
        {
            box.AppendText("\t" + Filename);

            try
            {
                FileInfo fInfo = new FileInfo(Filename);

                box.AppendText("\t" + Filename + ", " +
                    fInfo.Length.ToString() + ", " +
                    fInfo.CreationTime.ToShortDateString());

                FileVersionInfo fVersionInfo = FileVersionInfo.GetVersionInfo(Filename);
                box.AppendText(", " + fVersionInfo.FileVersion + ", " + fVersionInfo.ProductVersion);
            }
            catch (Exception)
            {
            }
        }

        private void VerifyFile(RichTextBox box, string Filename)
        {
            AppendText(box, Color.Green, " [REQUIRED]");
            RequiredFilesDictionary[Filename].Found = true;
            if (!CompareVersions(RequiredFilesDictionary[Filename].MinimumProductVersion, GetFileProductVersion(Filename)))
            {
                IssuesList.Add(new Issue(box.SelectionStart, RequiredFilesDictionary[Filename].Message));
                AppendText(box, Color.Red, " [BAD PRODUCT VERSION (Less than minimum)] " + GetMessageText(RequiredFilesDictionary[Filename].Message));
            }
            else
            {
                string MaxVersion = RequiredFilesDictionary[Filename].MaximumProductVersion;
                if (MaxVersion != null && !CompareVersions(GetFileProductVersion(Filename), MaxVersion))
                {
                    IssuesList.Add(new Issue(box.SelectionStart, RequiredFilesDictionary[Filename].Message));
                    AppendText(box, Color.Red, " [BAD PRODUCT VERSION (Greater than maximum)] " + GetMessageText(RequiredFilesDictionary[Filename].Message));
                }
                else
                {
                    IssuesList.Add(new Issue(box.SelectionStart));
                    AppendText(box, Color.Green, " [GOOD PRODUCT VERSION]");
                }
            }
        }

        private bool AppendSubDir(string SubDir, string Context)
        {
            foreach (string CurrentFile in Directory.GetFiles(SubDir))
            {
                AppendFile(StatusTextBox, CurrentFile);
                if (RequiredFilesDictionary.ContainsKey(CurrentFile))
                {
                    VerifyFile(StatusTextBox, CurrentFile);
                }
                StatusTextBox.AppendText("\n");
            }

            foreach (string CurrentDir in Directory.GetDirectories(SubDir))
            {
                try
                {
                    AppendSubDir(CurrentDir, Context);
                }
                catch (Exception ex)
                {
                    StatusTextBox.AppendText(CurrentDir + " ");
                    AppendText(StatusTextBox, Color.Orange, "[" + ex.Message + "]");
                    StatusTextBox.AppendText("\n");
                }
            }

            return true;
        }

        private void VerifyFiles()
        {
            try
            {
                AppendLineBreak(StatusTextBox);
                StatusTextBox.AppendText("Files Verification\n");
                AppendLineBreak(StatusTextBox);

                string Context = Variables["$(Context)"].Value;

                if (m_CommandLine.Verbose)
                {
                    AppendText(StatusTextBox, Color.Blue, "Context = " + Context);
                    StatusTextBox.AppendText("\n");
                }

                for (int i = 0; i < RequiredFiles.Count; i++)
                {
                    if (InContext(Context, RequiredFiles[i].Context))
                    {
                        string ResolvedFile = ResolveVariableString(RequiredFiles[i].File, RequiredFiles[i].Context);
                        if (m_CommandLine.Verbose)
                        {
                            AppendText(StatusTextBox, Color.Blue, "ResolvedFile = " + ResolvedFile);
                            StatusTextBox.AppendText("\n");
                        }
                        RequiredFilesDictionary.Add(ResolvedFile, RequiredFiles[i]);
                    }
                }

                List<string> Paths = GetVariable("$(InstallDir)", Context);

                if (Paths == null)
                {
                    IssuesList.Add(new Issue(StatusTextBox.SelectionStart, "MessageNoInstallDir"));
                    AppendText(StatusTextBox, Color.Red, "\t[NO INSTALL DIRECTORY FOUND] " + GetMessageText("MessageNoInstallDir") + "\n");
                }
                else
                {
                    foreach (string Path in Paths)
                    {
                        if (m_CommandLine.Verbose)
                        {
                            AppendText(StatusTextBox, Color.Blue, "InstallDir = " + Path);
                            StatusTextBox.AppendText("\n");
                        }

                        if (!Directory.Exists(Path))
                        {
                            IssuesList.Add(new Issue(StatusTextBox.SelectionStart, "MessageNoInstallDir"));
                            AppendText(StatusTextBox, Color.Red, "\t" + Path + " [NO INSTALL DIRECTORY FOUND] " + GetMessageText("MessageNoInstallDir") + "\n");
                        }
                        else
                        {
                            AppendSubDir(Path, Context);
                        }
                    }
                }

                foreach (KeyValuePair<string, RequiredFile> kv in RequiredFilesDictionary)
                {
                    if (!kv.Value.Found)
                    {
                        if (kv.Value.Context == null || InContext(Context, kv.Value.Context))
                        {
                            if (m_CommandLine.Verbose)
                            {
                                AppendText(StatusTextBox, Color.Blue, "Checking file = " + kv.Key);
                                StatusTextBox.AppendText("\n");
                            }

                            AppendFile(StatusTextBox, kv.Key);
                            try
                            {
                                if (!File.Exists(kv.Key))
                                {
                                    IssuesList.Add(new Issue(StatusTextBox.SelectionStart, kv.Value.Message));
                                    AppendText(StatusTextBox, Color.Red, " [REQUIRED][NOT FOUND] " + GetMessageText(kv.Value.Message));
                                }
                                else
                                {
                                    VerifyFile(StatusTextBox, kv.Key);
                                }
                            }
                            catch (Exception)
                            {
                                IssuesList.Add(new Issue(StatusTextBox.SelectionStart, kv.Value.Message));
                                AppendText(StatusTextBox, Color.Red, " [REQUIRED][NOT FOUND] " + GetMessageText(kv.Value.Message));
                            }
                            StatusTextBox.AppendText("\n");
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                if (m_CommandLine.Verbose)
                {
                    AppendText(StatusTextBox, Color.Blue, "Exception: " + ex.Message);
                    StatusTextBox.AppendText("\n");
                }
                MessageBox.Show(ex.Message, Application.ProductName, MessageBoxButtons.OK);
            }
        }

        private bool AppendSubKey(RegistryKey SubKey, int Tabs)
        {
            string TabsString = "";
            for (int i = 0; i < Tabs - 1; i++)
                TabsString += "\t";
            StatusTextBox.AppendText(TabsString + SubKey.Name);
            if (RequiredRegistryValuesDictionary.ContainsKey(SubKey.Name))
            {
                IssuesList.Add(new Issue(StatusTextBox.SelectionStart));
                if (RequiredRegistryValuesDictionary[SubKey.Name].Required)
                    AppendText(StatusTextBox, Color.Green, " [REQUIRED]");
                else
                    AppendText(StatusTextBox, Color.Green, " [OPTIONAL]");
                RequiredRegistryValuesDictionary[SubKey.Name].Found = true;
                PerformOperation(RequiredRegistryValuesDictionary[SubKey.Name], null);
            }
            StatusTextBox.AppendText("\n");
            TabsString += "\t";

            foreach (string value in SubKey.GetValueNames())
            {
                StatusTextBox.AppendText(TabsString + value.ToString() + " = " + SubKey.GetValue(value).ToString());
                string dk = SubKey.Name + "\\" + value;
                if (RequiredRegistryValuesDictionary.ContainsKey(dk))
                {
                    IssuesList.Add(new Issue(StatusTextBox.SelectionStart));
                    if (RequiredRegistryValuesDictionary[dk].Required)
                        AppendText(StatusTextBox, Color.Green, " [REQUIRED]");
                    else
                        AppendText(StatusTextBox, Color.Green, " [OPTIONAL]");
                    RequiredRegistryValuesDictionary[dk].Found = true;
                    PerformOperation(RequiredRegistryValuesDictionary[dk], SubKey.GetValue(value).ToString());
                }
                StatusTextBox.AppendText("\n");
            }

            foreach (string SubKeyName in SubKey.GetSubKeyNames())
            {
                try
                {
                    RegistryKey SubSubKey = SubKey.OpenSubKey(SubKeyName);
                    if (SubSubKey != null)
                        AppendSubKey(SubSubKey, Tabs + 1);
                }
                catch (Exception ex)
                {
                    StatusTextBox.AppendText(TabsString + SubKey.Name + "\\" + SubKeyName + " ");
                    AppendText(StatusTextBox, Color.Orange, "[" + ex.Message + "]");
                    StatusTextBox.AppendText("\n");
                }
            }

            return true;
        }

        private void PerformOperation (RegistryValue rv, object o)
        {
            switch (rv.Operation)
            {
                case RegistryValue.OperationType.CompareValue:
                    {
                        if (rv.Argument1 == o.ToString())
                        {
                            AppendText(StatusTextBox, Color.Green, "[GOOD VALUE]");
                        }
                        else
                        {
                            IssuesList.Add(new Issue(StatusTextBox.SelectionStart, rv.Message));
                            AppendText(StatusTextBox, Color.Red, "[BAD VALUE] " + GetMessageText(rv.Message));
                        }
                    }
                    break;
                case RegistryValue.OperationType.CompareVersion:
                    {
                        if (CompareVersions(rv.Argument1, o.ToString()))
                        {
                            AppendText(StatusTextBox, Color.Green, "[GOOD VERSION]");
                        }
                        else
                        {
                            IssuesList.Add(new Issue(StatusTextBox.SelectionStart, rv.Message));
                            AppendText(StatusTextBox, Color.Red, "[BAD VERSION] " + GetMessageText(rv.Message));
                        }
                    }
                    break;
                case RegistryValue.OperationType.SetVariable:
                    {
                        SetVariable(rv.Argument1, o.ToString());
                        if (m_CommandLine.Verbose)
                        {
                            AppendText(StatusTextBox, Color.Blue, "Set variable " + rv.Argument1);
                            StatusTextBox.AppendText("\n");
                        }
                    }
                    break;
                case RegistryValue.OperationType.SetDirVariable:
                    {
                        string dir = o.ToString();
                        dir = dir.TrimEnd('\\');
                        SetVariable(rv.Argument1, rv.Context, dir);
                        if (m_CommandLine.Verbose)
                        {
                            AppendText(StatusTextBox, Color.Blue, "Set Dir " + rv.Argument1 + " to " + dir + " Context = " + rv.Context);
                            StatusTextBox.AppendText("\n");
                        }
                    }
                    break;
                case RegistryValue.OperationType.SetFlagVariable:
                    {
                        SetVariable(rv.Argument1, "true");
                        if (m_CommandLine.Verbose)
                        {
                            AppendText(StatusTextBox, Color.Blue, "Flag set " + rv.Argument1);
                            StatusTextBox.AppendText("\n");
                        }
                    }
                    break;
                case RegistryValue.OperationType.SetContextVariable:
                    {
                        AppendVariable("$(Context)", rv.Argument1);
                        if (m_CommandLine.Verbose)
                        {
                            AppendText(StatusTextBox, Color.Blue, "Context set to " + rv.Argument1);
                            StatusTextBox.AppendText("\n");
                        }
                    }
                    break;
                case RegistryValue.OperationType.TestAndSetContextVariable:
                    {
                        string Context = Variables["$(Context)"].Value;
                        if (!InContext(Context, rv.Argument1))
                            AppendVariable("$(Context)", rv.Argument2);
                        if (m_CommandLine.Verbose)
                        {
                            AppendText(StatusTextBox, Color.Blue, "Tested and Context set to " + rv.Argument2);
                            StatusTextBox.AppendText("\n");
                        }
                    }
                    break;
            }
        }

        private bool InContext (string Context, string Subcontext)
        {
            if (string.IsNullOrEmpty(Subcontext))
                return true;
            if (string.IsNullOrEmpty(Context))
                return false;

            char[] delimiters = new char[] { ',' };
            string[] ParsedContext = Context.Split(delimiters);
            string[] ParsedSubcontext = Subcontext.Split(delimiters);

            foreach (string sub in ParsedSubcontext)
            {
                bool Found = false;
                foreach (string c in ParsedContext)
                    if (c.Trim() == sub.Trim())
                        Found = true;
                if (!Found)
                    return false;
            }
            return true;
        }

        RegistryKey GetRegistryKey(ref string spec)
        {
            RegistryKey Key = null;
            if (spec.Contains("HKEY_LOCAL_MACHINE"))
            {
                spec = spec.Replace("HKEY_LOCAL_MACHINE\\", "");
                Key = Registry.LocalMachine;
            }
            else if (spec.Contains("HKEY_CLASSES_ROOT"))
            {
                spec = spec.Replace("HKEY_CLASSES_ROOT\\", "");
                Key = Registry.ClassesRoot;
            }
            else if (spec.Contains("HKEY_CURRENT_USER"))
            {
                spec = spec.Replace("HKEY_CURRENT_USER\\", "");
                Key = Registry.CurrentUser;
            }
            return Key;
        }

        void DoRegistryFirstPass()
        {
            for (int i = 0; i < RequiredRegistryValues.Count; i++)
            {
                RegistryValue rv = RequiredRegistryValues[i];

                if ((rv.Operation != RegistryValue.OperationType.SetFlagVariable) &&
                    (rv.Operation != RegistryValue.OperationType.SetContextVariable) &&
                    (rv.Operation != RegistryValue.OperationType.TestAndSetContextVariable) &&
                    (rv.Operation != RegistryValue.OperationType.SetDirVariable))
                    continue;

                string Context = Variables["$(Context)"].Value;
                try
                {
                    if (InContext(Context, rv.Context))
                    {
                        if (rv.Operation == RegistryValue.OperationType.TestAndSetContextVariable)
                        {
                            RequiredRegistryValues[i].Found = true;
                            PerformOperation(rv, null);
                        }
                        else
                        {
                            string SubKey = ResolveVariableString(rv.ValueName, Context);

                            RegistryKey Key = GetRegistryKey(ref SubKey);
                            if (Key == null)
                                continue;

                            string KeyName = "";
                            string ValueName = "";
                            if (rv.Part == RegistryValue.PartType.Key)
                                KeyName = SubKey;
                            else
                            {
                                string[] Keys = SubKey.Split('\\');
                                for (int j = 0; j < Keys.Length - 1; j++)
                                {
                                    if (!string.IsNullOrEmpty(KeyName))
                                        KeyName += "\\";
                                    KeyName += Keys[j] + "\\";
                                }
                                ValueName = Keys[Keys.Length - 1];
                            }

                            Key = Key.OpenSubKey(KeyName);
                            if (Key == null)
                                continue;

                            if (rv.Part == RegistryValue.PartType.Key)
                            {
                                RequiredRegistryValues[i].Found = true;
                                PerformOperation(rv, null);
                            }
                            else
                            {
                                if (ValueName == "(Default)")
                                    ValueName = "";
                                object o = Key.GetValue(ValueName);
                                if (o != null)
                                {
                                    RequiredRegistryValues[i].Found = true;
                                    PerformOperation(rv, o);
                                }
                                else
                                {
                                    if (m_CommandLine.Verbose)
                                    {
                                        AppendText(StatusTextBox, Color.Blue, KeyName + ValueName + "Not found");
                                        StatusTextBox.AppendText("\n");
                                    }
                                }
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message, Application.ProductName, MessageBoxButtons.OK);
                }
            }
        }

        private void VerifyRegistry()
        {
            AppendLineBreak(StatusTextBox);
            StatusTextBox.AppendText("Registry Verification\n");
            AppendLineBreak(StatusTextBox);

            DoRegistryFirstPass();

            string Context = "";
            if (Variables.ContainsKey("$(Context)"))
                Context = Variables["$(Context)"].Value;

            for (int i = 0; i < RequiredRegistryValues.Count; i++)
            {
                if (string.IsNullOrEmpty(RequiredRegistryValues[i].ValueName))
                    continue;
                try 
	            {	        
                    if (m_CommandLine.Verbose)
                    {
                        AppendText(StatusTextBox, Color.Blue, RequiredRegistryValues[i].ValueName);
                        StatusTextBox.AppendText("\n");
                    }
                    if (InContext(Context, RequiredRegistryValues[i].Context))
                    {
                        string ResolvedValue = ResolveVariableString(RequiredRegistryValues[i].ValueName, Context);
                        if (RequiredRegistryValuesDictionary.ContainsKey(ResolvedValue))
                            RequiredRegistryValuesDictionary[ResolvedValue] = RequiredRegistryValues[i];
                        else
                            RequiredRegistryValuesDictionary.Add(ResolvedValue, RequiredRegistryValues[i]);
                    }
                }
                catch (Exception ex)
                {
                    if (m_CommandLine.Verbose)
                    {
                        AppendText(StatusTextBox, Color.Blue, "Exception: " + ex.Message);
                        StatusTextBox.AppendText("\n");
                    }
                    MessageBox.Show(ex.Message, Application.ProductName, MessageBoxButtons.OK);
                }
            }

            try
            {
                List<string> BaseSubKeys = GetVariable("$(BaseKey)", Context);
                if (BaseSubKeys != null)
                {
                    foreach(string BaseSubKey in BaseSubKeys)
                    {
                        if (!string.IsNullOrEmpty(BaseSubKey))
                        {
                            string subkey = BaseSubKey;
                            RegistryKey Key = GetRegistryKey(ref subkey);
                            Key = Key.OpenSubKey(subkey);
                            if (Key == null)
                            {
                                IssuesList.Add(new Issue(StatusTextBox.SelectionStart, "MessageBaseKeyNotFound"));
                                AppendText(StatusTextBox, Color.Red, "\t" + subkey + " [BASE KEY NOT FOUND] " + GetMessageText("MessageBaseKeyNotFound") + "\n");
                            }
                            else
                            {
                                AppendSubKey(Key, 1);
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                if (m_CommandLine.Verbose)
                {
                    AppendText(StatusTextBox, Color.Blue, "Exception: " + ex.Message);
                    StatusTextBox.AppendText("\n");
                }
                MessageBox.Show(ex.Message, Application.ProductName, MessageBoxButtons.OK);
            }

            foreach (KeyValuePair<string, RegistryValue> rv in RequiredRegistryValuesDictionary)
            {
               Context = Variables["$(Context)"].Value;
               try
                {
                    if ((!rv.Value.Found) && InContext(Context, rv.Value.Context))
                    {
                        string SubKey = ResolveVariableString(rv.Key, Context);

                        RegistryKey Key = GetRegistryKey(ref SubKey);
                        if (Key == null)
                            continue;

                        string KeyName = "";
                        string ValueName = "";
                        if (rv.Value.Part == RegistryValue.PartType.Key)
                            KeyName = SubKey;
                        else
                        {
                            string[] Keys = SubKey.Split('\\');
                            for (int j = 0; j < Keys.Length - 1; j++)
                            {
                                if (!string.IsNullOrEmpty(KeyName))
                                    KeyName += "\\";
                                KeyName += Keys[j] + "\\";
                            }
                            ValueName = Keys[Keys.Length - 1];
                        }
                        
                        Key = Key.OpenSubKey(KeyName);
                        if (Key == null)
                        {
                            if (rv.Value.Required)
                            {
                                IssuesList.Add(new Issue(StatusTextBox.SelectionStart, rv.Value.Message));
                                AppendText(StatusTextBox, Color.Red, "\t" + rv.Key + " [KEY NOT FOUND] " + GetMessageText(rv.Value.Message) + "\n");
                            }
                            continue;
                        }

                        if (rv.Value.Part == RegistryValue.PartType.Key)
                        {
                            if (rv.Value.Required)
                            {
                                IssuesList.Add(new Issue(StatusTextBox.SelectionStart, rv.Value.Message));
                                AppendText(StatusTextBox, Color.Red, "\t" + rv.Key + " [KEY NOT FOUND] " + GetMessageText(rv.Value.Message) + "\n");
                            }
                        }
                        else
                        {
                            if (ValueName == "(Default)")
                                ValueName = "";
                            object o = Key.GetValue(ValueName);
                            if (o == null)
                            {
                                if (rv.Value.Required)
                                {
                                    IssuesList.Add(new Issue(StatusTextBox.SelectionStart, rv.Value.Message));
                                    AppendText(StatusTextBox, Color.Red, "\t" + rv.Key + " [VALUE NOT FOUND] " + GetMessageText(rv.Value.Message) + "\n");
                                }
                            }
                            else
                            {
                                AppendText(StatusTextBox, Color.Green, "\t" + rv.Key + "=" + o.ToString());
                                if (rv.Value.Required)
                                    AppendText(StatusTextBox, Color.Green, " [REQUIRED]");
                                else
                                    AppendText(StatusTextBox, Color.Green, " [OPTIONAL]");

                                rv.Value.Found = true;
                                PerformOperation(rv.Value, o);
                            }
                            StatusTextBox.AppendText("\n");
                        }
                    }
                }
                catch (Exception ex)
                {
                    if (m_CommandLine.Verbose)
                    {
                        AppendText(StatusTextBox, Color.Blue, "Exception: " + ex.Message);
                        StatusTextBox.AppendText("\n");
                    }
                    MessageBox.Show(ex.Message, Application.ProductName, MessageBoxButtons.OK);
                }
            }
        }

        public bool IsProcessOpen(string name)
        {
            foreach (Process clsProcess in Process.GetProcesses())
            {
                if (System.String.Compare(clsProcess.ProcessName, name, true) == 0)
                {
                    return true;
                }
            }
            return false;
        }

        private void CheckCurrentState()
        {
            AppendLineBreak(StatusTextBox);
            StatusTextBox.AppendText("Checking Current State\n");
            AppendLineBreak(StatusTextBox);

            string Context = Variables["$(Context)"].Value;
            for (int i = 0; i < RequiredProcesses.Count; i++)
            {
                if (RequiredProcesses[i].Context == null || InContext(Context, RequiredProcesses[i].Context))
                {
                    StatusTextBox.AppendText("\t" + RequiredProcesses[i].Name);
                    if (IsProcessOpen(RequiredProcesses[i].Name))
                    {
                        IssuesList.Add(new Issue(StatusTextBox.SelectionStart));
                        AppendText(StatusTextBox, Color.Green, " [RUNNING]");
                    }
                    else
                    {
                        IssuesList.Add(new Issue(StatusTextBox.SelectionStart, RequiredProcesses[i].Message));
                        AppendText(StatusTextBox, Color.Red, " [NOT RUNNING] " + GetMessageText(RequiredProcesses[i].Message));
                    }
                    StatusTextBox.AppendText("\n");
                }
            }
        }

        private void ShowAnalysis ()
        {
            AppendLineBreak(StatusTextBox);
            StatusTextBox.AppendText("Analysis\n");
            AppendLineBreak(StatusTextBox);

            string Context = Variables["$(Context)"].Value;

            StatusTextBox.AppendText("Context = " + Context + "\n");
        }


        void SelectCurrentIssue()
        {
            StatusTextBox.Select(IssuesList[LastIssue].Position, 1); 
            int FirstChar = StatusTextBox.GetFirstCharIndexOfCurrentLine();
            StatusTextBox.Select(FirstChar, IssuesList[LastIssue].Position - FirstChar);
            StatusTextBox.SelectionBackColor = DefaultBackColor;
            StatusTextBox.Select();

            LastIssue = CurrentIssue;

            StatusTextBox.Select(IssuesList[CurrentIssue].Position, 1); 
            FirstChar = StatusTextBox.GetFirstCharIndexOfCurrentLine();
            StatusTextBox.Select(FirstChar, IssuesList[CurrentIssue].Position - FirstChar);
            StatusTextBox.SelectionBackColor = Color.Yellow;
            StatusTextBox.Select();
        }

#region Menu
        private void CopyToClipBoardButton_Click(object sender, EventArgs e)
        {
            StatusTextBox.SelectAll();
            StatusTextBox.Copy();
        }

        private void NextButton_Click(object sender, EventArgs e)
        {
            if (CurrentIssue == IssuesList.Count - 1)
            {
                if (MessageBox.Show("You have reached the last issue, do you wish to start again at the beginning?", Application.ProductName, MessageBoxButtons.YesNo) == DialogResult.Yes)
                    CurrentIssue = 0;
            }
            else 
                CurrentIssue++;
            IssuesListView.Items[CurrentIssue].Selected = true;
        }

        private void PreviousButton_Click(object sender, EventArgs e)
        {
            if (CurrentIssue == 0)
            {
                if (MessageBox.Show("This is the first issue, do you wish to go to the last issue?", Application.ProductName, MessageBoxButtons.YesNo) == DialogResult.Yes)
                    CurrentIssue = IssuesList.Count - 1;
            }
            else
                CurrentIssue--;
            IssuesListView.Items[CurrentIssue].Selected = true;
        }

        private void SaveFile(string FileName)
        {
            if (Path.GetExtension(FileName) == ".rtf")
                StatusTextBox.SaveFile(FileName, RichTextBoxStreamType.RichText);
            else
                StatusTextBox.SaveFile(FileName, RichTextBoxStreamType.PlainText);
        }

        private void SaveButton_Click(object sender, EventArgs e)
        {
            SaveFileDialog dlg = new SaveFileDialog();

            dlg.Filter = "txt files (*.txt)|*.txt|Rich Text (*.rtf)|*.rtf";
            dlg.FilterIndex = 2;

            if (dlg.ShowDialog() == DialogResult.OK)
            {
                SaveFile(dlg.FileName);
            }
        }
#endregion // Menu


        public bool LoadConfiguration (string Filename)
        {
            bool Result = true;

            if (!File.Exists(Filename))
                return false;

            try
            {
                XmlDocument doc = new XmlDocument();
                FileStream stream = new FileStream(Filename, FileMode.Open, FileAccess.Read);
                doc.Load(stream);

                XmlNodeList nodes;
                char[] delimiters = new char[] { ',' };

                nodes = doc.GetElementsByTagName("Variables");
                if (nodes.Count > 0)
                {
                    Variables.Clear();
                    foreach (XmlNode node in nodes)
                    {
                        foreach (XmlNode childnode in node.ChildNodes)
                        {
                            string Name = "";
                            Variable variable = new Variable();
                            foreach (XmlNode grandchildnode in childnode.ChildNodes)
                            {
                                string s = grandchildnode.Name;
                                switch (s)
                                {
                                    case "Name":
                                        Name = grandchildnode.InnerText;
                                        break;
                                    case "Value":
                                        variable.Value = grandchildnode.InnerText;
                                        break;
                                    case "ContextValues":
                                        {
                                            foreach (XmlNode greatgrandchildnode in grandchildnode.ChildNodes)
                                            {
                                                ContextValue cv = new ContextValue();

                                                foreach (XmlNode greatgreatgrandchildnode in greatgrandchildnode.ChildNodes)
                                                {
                                                    switch (greatgreatgrandchildnode.Name)
                                                    {
                                                        case "Context":
                                                            cv.Context = greatgreatgrandchildnode.InnerText;
                                                            break;
                                                        case "Value":
                                                            cv.Value = greatgreatgrandchildnode.InnerText;
                                                            break;
                                                    }
                                                }

                                                if (cv.IsValid())
                                                    variable.SetContextValue(cv);
                                            }
                                        }
                                        break;
                                }
                            }
                            if (!string.IsNullOrEmpty(Name) && variable.IsValid())
                                Variables.Add(Name, variable);
                        }
                    }
                }

                nodes = doc.GetElementsByTagName("InstalledComponents");
                if (nodes.Count > 0)
                {
                    RequiredInstalledComponents.Clear();
                    foreach (XmlNode node in nodes)
                    {
                        foreach (XmlNode childnode in node.ChildNodes)
                        {
                            RequiredInstalledComponent rc = new RequiredInstalledComponent();

                            foreach (XmlNode grandchildnode in childnode.ChildNodes)
                            {
                                string s = grandchildnode.Name;
                                switch (s)
                                {
                                    case "Name":
                                        rc.Name = grandchildnode.InnerText;
                                        break;
                                    case "Message":
                                        rc.Message = grandchildnode.InnerText;
                                        break;
                                    case "Context":
                                        rc.Context = grandchildnode.InnerText;
                                        break;
                                    case "MinimumProductVersion":
                                        rc.MinimumProductVersion = grandchildnode.InnerText;
                                        break;
                                    case "MaximumProductVersion":
                                        rc.MaximumProductVersion = grandchildnode.InnerText;
                                        break;
                                }
                            }

                            if (rc.IsValid())
                                RequiredInstalledComponents.Add(rc);
                        }
                    }
                }

                nodes = doc.GetElementsByTagName("Registry");
                if (nodes.Count > 0)
                {
                    RequiredRegistryValues.Clear();
                    foreach (XmlNode node in nodes)
                    {
                        foreach (XmlNode childnode in node.ChildNodes)
                        {
                            RegistryValue rv = new RegistryValue();

                            foreach (XmlNode grandchildnode in childnode.ChildNodes)
                            {
                                string s = grandchildnode.Name;
                                switch (s)
                                {
                                    case "Name":
                                        rv.ValueName = grandchildnode.InnerText;
                                        break;
                                    case "Message":
                                        rv.Message = grandchildnode.InnerText;
                                        break;
                                    case "Part":
                                        rv.Part = RegistryValue.ParsePartType(grandchildnode.InnerText);
                                        break;
                                    case "Operation":
                                        rv.Operation = RegistryValue.ParseOperationType(grandchildnode.InnerText);
                                        break;
                                    case "Argument":
                                    case "Argument1":
                                        rv.Argument1 = grandchildnode.InnerText;
                                        break;
                                    case "Argument2":
                                        rv.Argument2 = grandchildnode.InnerText;
                                        break;
                                    case "Context":
                                        rv.Context = grandchildnode.InnerText;
                                        break;
                                    case "Required":
                                        rv.Required = bool.Parse(grandchildnode.InnerText);
                                        break;
                                }
                            }

                            if (rv.IsValid())
                                RequiredRegistryValues.Add(rv);
                        }
                    }
                }

                nodes = doc.GetElementsByTagName("Files");
                if (nodes.Count > 0)
                {
                    RequiredFiles.Clear();
                    foreach (XmlNode node in nodes)
                    {
                        foreach (XmlNode childnode in node.ChildNodes)
                        {
                            RequiredFile rf = new RequiredFile();

                            foreach (XmlNode grandchildnode in childnode.ChildNodes)
                            {
                                string s = grandchildnode.Name;
                                switch (s)
                                {
                                    case "File":
                                        rf.File = grandchildnode.InnerText;
                                        break;
                                    case "Context":
                                        rf.Context = grandchildnode.InnerText;
                                        break;
                                    case "Message":
                                        rf.Message = grandchildnode.InnerText;
                                        break;
                                    case "MinimumProductVersion":
                                        rf.MinimumProductVersion = grandchildnode.InnerText;
                                        break;
                                    case "MaximumProductVersion":
                                        rf.MaximumProductVersion = grandchildnode.InnerText;
                                        break;
                                }
                            }

                            if (rf.IsValid())
                                RequiredFiles.Add(rf);
                        }
                    }
                }

                nodes = doc.GetElementsByTagName("Processes");
                if (nodes.Count > 0)
                {
                    RequiredProcesses.Clear();
                    foreach (XmlNode node in nodes)
                    {
                        foreach (XmlNode childnode in node.ChildNodes)
                        {
                            RequiredProcess rp = new RequiredProcess();

                            foreach (XmlNode grandchildnode in childnode.ChildNodes)
                            {
                                string s = grandchildnode.Name;
                                switch (s)
                                {
                                    case "Name":
                                        rp.Name = grandchildnode.InnerText;
                                        break;
                                    case "Context":
                                        rp.Context = grandchildnode.InnerText;
                                        break;
                                    case "Message":
                                        rp.Message = grandchildnode.InnerText;
                                        break;
                                }
                            }

                            if (rp.IsValid())
                                RequiredProcesses.Add(rp);
                        }
                    }
                }

                nodes = doc.GetElementsByTagName("Messages");
                if (nodes.Count > 0)
                {
                    Messages.Clear();
                    foreach (XmlNode node in nodes)
                    {
                        foreach (XmlNode childnode in node.ChildNodes)
                        {
                            Message Message = new Message();

                            foreach (XmlNode grandchildnode in childnode.ChildNodes)
                            {
                                string s = grandchildnode.Name;
                                switch (s)
                                {
                                    case "Text":
                                        Message.Text = grandchildnode.InnerText;
                                        break;
                                    case "Type":
                                        Message.Type = grandchildnode.InnerText;
                                        break;
                                }
                            }

                            if (Message.IsValid())
                                Messages.Add(childnode.Name, Message);
                        }
                    }
                }
            }
            catch (XmlException xmlex)
            {
                MessageBox.Show(xmlex.Message, Application.ProductName, MessageBoxButtons.OK);
                Trace.TraceError(xmlex.Message);
                Result = false;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, Application.ProductName, MessageBoxButtons.OK);
                Trace.TraceError(ex.Message);
                Result = false;
            }
            return Result;
        }

        private void IssuesListView_SelectedIndexChanged(object sender, EventArgs e)
        {
            ListView.SelectedListViewItemCollection lvis = IssuesListView.SelectedItems;
            if (lvis.Count > 0)
            {
                CurrentIssue = int.Parse(lvis[0].Text);
                SelectCurrentIssue();
                IssuesListView.EnsureVisible(CurrentIssue);
                IssuesListView.Focus();
            }
        }

        private void UpdateIssuesListView()
        {
            for (int i = 0; i < IssuesList.Count; i++)
            {
                ListViewItem lvi = IssuesListView.Items.Add(i.ToString());
                lvi.Tag = IssuesList[i].Position;
                string Text = "Item Passed";
                string Type = "";
                if (!string.IsNullOrEmpty(IssuesList[i].Message))
                {
                    Text = "Issue has no description";
                    if (!string.IsNullOrEmpty(IssuesList[i].Message))
                    {
                        if (Messages.ContainsKey(IssuesList[i].Message))
                            Text = Messages[IssuesList[i].Message].Text;
                    }
                    if (!string.IsNullOrEmpty(IssuesList[i].Message))
                    {
                        if (Messages.ContainsKey(IssuesList[i].Message))
                            Type = Messages[IssuesList[i].Message].Type;
                    }
                }
                lvi.SubItems.Add(Type);
                lvi.SubItems.Add(Text);
            }
        }

        private string GetMessageText(string MessageID)
        {
            string Text = "";
            if (Messages.ContainsKey(MessageID))
                Text = Messages[MessageID].Text;

            return Text;
        }

    }
}
